package com.sxf.rental.security;

import cn.hutool.core.util.StrUtil;
import com.sxf.rental.utils.JwtUtils;
import com.sxf.rental.utils.RedisUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

//OncePerRequestFilter是Spring提供的一个抽象类，它实现了OncePerRequestFilter接口，
// 它的作用是在每次请求时只执行一次过滤器逻辑，避免重复执行。
//在Spring security中，可以用来过滤请求，它通常用于验证用户身份和权限，比如验证用户是否登录、是否有权限访问某个资源等。
@Component
public class VerifyTokenFilter extends OncePerRequestFilter {

    @Value("${request.login-url}")
    private  String loginUrl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;
    @Resource
    private  LoginFailHandler loginFailHandler;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String url = request.getRequestURI();
        if (!StrUtil.equals(url,loginUrl)){
            //校验Token
            try {
                validateToken(request, response);
            }catch (AuthenticationException e){
                loginFailHandler.onAuthenticationFailure(request,response,e);
            }
        }
        doFilter(request,response,filterChain);
    }

    private void validateToken(HttpServletRequest request,HttpServletResponse  response) throws AuthenticationException {
        String token = request.getHeader("token");
        if(StrUtil.isEmpty(token)){
            token= request.getParameter("token");
        }
        if (StrUtil.isEmpty(token)){
            throw new CustomerAuthenticationException("token为空");
        }
        //如果Token存在,需要和Redis中和Token比较
        String tokenKey="token:"+token;
        String tokenValue=redisUtils.get(tokenKey);
        if (StrUtil.isEmpty(tokenValue)){
            throw new CustomerAuthenticationException("token已过期");
        }
        if (!StrUtil.equals(token,tokenValue)){
            throw new CustomerAuthenticationException("token错误");
        }
        String username= JwtUtils.parseToken(token).getClaim("username").toString();

        if (StrUtil.isEmpty(username)){
            throw new CustomerAuthenticationException("token解析错误");
        }
        UserDetails userDetails = customerUserDetailsService.loadUserByUsername(username);
        if (userDetails==null){
            throw new CustomerAuthenticationException("用户不存在");
        }
        //创建并设置认证信息
        UsernamePasswordAuthenticationToken authenticationToken=
                new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        //将认证信息设置到SecurityContextHolder中
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }
}
